#pragma mode( separator(.,;) integer(h32) )
local pbank:=10000,pbet:=10,pminbet:=10,pmaxbet:=1000;
local orig_HFormat,orig_HAngle,orig_AAngle,orig_AFormat;
local location,orig_bank,orig_bet,bucket,devi;
local ace_split,ace,split,saved;

local desktop,card_back,grad1,grad2;
local statusarea:=#F2DDA2h,linecolor:=#969696h,nocolor:=#50D40h,card_front:=#E9F5F1h;
local red:=#FF0000h,black:=#0h,white:=#FFFFFFh,mag:=#FA02E1h;

local STAT_WIN:=1,STAT_LOSE:=2,STAT_DBLWIN:=3,STAT_DBLLOSS:=4;
local STAT_BJ:=5,STAT_SURR:=6,STAT_BUST:=7,STAT_TIE:=8;
local STAT_SPLIT:=9,STAT_INSWON:=10,STAT_INSLOST:=11;

local STATE_TOT:=1,STATE_ACE:=2,STATE_BUST:=3,STATE_BJ:=4;
local STATE_SPLIT:=5,STATE_SURR:=6,STATE_DBL:=7,STATE_INS:=8;
local STATE_TC:=9,STATE_RESULT:=10;

local cardcount,ndeck,unseen,seen,dark;
local ccount,offer_ins,cut_card,true_count;
local show_hint,auto_bet,meter,show_bet,bad_bet,bad_ins;

local otto,otto_wait_val,otto_wait;
local SUIT,S_HEART:=2,S_DIAMOND:=3;

local stat_collect_val,stat_collect;
local strat_follow,strat_total,kresolved;
local rounds,deck_rounds,round_result,BS_adv;
local max_dx:=319,soft_dy:=219,dx:=319,dy:=239;
local DELTAX:=34,DELTAY=48; //size of card
local STATUSX:=5,STATUSY:=155;

local CMD_HIT:=1,CMD_STAND:=2,CMD_DBL:=3,CMD_SPLIT:=4,CMD_SURR:=5;
local CMD_YES:=1,CMD_NO:=2,CMD_DECK:=1,CMD_DISC:=2,CMD_PLAY:=1;
local CMD_DBL_HIT:=7,CMD_DBL_STAND:=8,CMD_PREF:=4;
local CMD_BET:=2,CMD_DEAL:=1,CMD_QUIT:=5,CMD_STAT:=6,CMD_CONT:=6;
local CMD_GAME:=3,CMD_LOAD:=4,CMD_COLOR:=3,CMD_HELP:=2;
local CMD_NONE:=99,CMD_NEG:=-0.1,CMD_POS:=0.1;

local MONEY_BET:=1,MONEY_BANK:=2,MONEY_MIN:=3,MONEY_MAX:=4;

local bstrat,stat,money,pref_money,orig_deck,lastx,last_pstatus;
local card_offset:={-2,0,2,0};
local empty_deck_shuffle,dealer_card_seen,moon;
local LART,BITART,DSTATE,PSTATE;
local PHAND,DHAND,SDECK,DISC;

EXPORT BLKJKsave,BLKJKpref,BLKJKdata;

EXPORT BLKJK()
begin
   local action:=CMD_DEAL;

   INIT();
   if welcome() <> CMD_QUIT then
      if NOT shuffle() then welback(); action:=INTERMISSION(); end;
      while action <> CMD_QUIT do
         if shuffle() then MAKEDECK(); action:=INTERMISSION(); end;
         if action == CMD_DEAL then
            DEAL();
            ONE_ROUND();
            END_ROUND();
            action:=INTERMISSION();
         end;
      end;
   end;

   restore_format();
end;


welback()
begin
   copy_desktop(); PSTATUS("Welcome back!",1);
   if RANDINT(1,6) == 1 then random_phrase(); end;
end;


INIT()
begin
   STARTAPP("Function");
   STARTVIEW(-7);
   DRAWMENU("","","Please","wait");
   RANDSEED;
   init_format();
   init_gvars();
   init_strat();
   IFTE(TYPE(BLKJKpref) == 6 AND SIZE(BLKJKpref) == 15,pref_load(),desktop_color());
   desktop_art();
end;


ONE_ROUND()
begin
   local curr_hand:=1,next_hand,action,hint;
   DIMGROB_P(G7,dx+1,76,nocolor);
   rounds:=rounds+1;
   deck_rounds:=deck_rounds+1;

   repeat
      next_hand:=0;

      if PSTATE(curr_hand,STATE_SPLIT) AND SIZE(PHAND(curr_hand)) == 2 then
         PRINT_PMSG(curr_hand);
         if action <> CMD_SPLIT then disp_phand(curr_hand); end;
      end;

      if offer_ins then
         get_ins(curr_hand);
         if PSTATE(curr_hand,STATE_INS) then settle_ins(curr_hand); end;
      end;

      if PSTATE(curr_hand,STATE_BJ) OR DSTATE(STATE_BJ) then
         PRINT_MSGBOX(IFTE(PSTATE(curr_hand,STATE_BJ),"Natural",""),[location(1),location(2)+1],9,17,0,0);
         PSTAND();
         return;
      end;

      split:=IFTE(SIZE(PHAND(curr_hand)) == 2,CANSPLIT(curr_hand),0);

      hint:=basic_strat(curr_hand);
      action:=GETACT("play",{hint,SIZE(PHAND(curr_hand)),split});
      basic_strat_stats(action,hint);
      PSTATUS("",4);

      ace_split:=(ace_split AND action == CMD_SPLIT);

      case
      if action == CMD_HIT then
         PHIT(curr_hand);
      end;
      if action == CMD_STAND then
         if SIZE(PHAND) == curr_hand then PSTAND(); end;
         next_hand:=1;
      end;
      if action == CMD_SPLIT then
         PSPLIT(curr_hand);
      end;
      if action == CMD_DBL then
         PSTATE(curr_hand,STATE_DBL):=1;
         PHIT(curr_hand);
      end;
      if action == CMD_SURR then
         PSTATE(curr_hand,STATE_SURR):=1;
         END_HAND(curr_hand,"Surrender"); next_hand:=1;
      end;
      end;

      case
      if PSTATE(curr_hand,STATE_BUST) then
         END_HAND(curr_hand,"Bust"); next_hand:=1;
      end;
      if action == CMD_DBL then
         END_HAND(curr_hand,""); next_hand:=1;
      end;
      end;

      curr_hand:=curr_hand+next_hand;
   until curr_hand > SIZE(PHAND) OR ace_split;
end;


END_HAND(hand,txt)
begin
   PRINT_MSGBOX(txt,[location(1),location(2)+1],IFTE(PSTATE(hand,STATE_DBL),23,9),17,0,0);
   if SIZE(PHAND) > 1 AND SIZE(PHAND) == hand then CONT(); end;
   IFTE(SIZE(PHAND) == hand,PSTAND(),CONT());
end;


CONT()
begin
   while GETACT("cont",{}) <> CMD_CONT do end;
end;


CLSTAT()
begin
   RECT_P(0,STATUSY-3,dx,soft_dy,statusarea);
end;


PRINT_PMSG(item)
begin
   local txt,x:=12,y:=78,value,th:={"st","nd","rd"};
   local t1:=" Player's ",t2:="th",t3:=" of "+SIZE(PHAND)+" hands ";
   if lastx(1) <> 0 then
      BLIT_P(x,y-1,G3,x,y-1,x+lastx(1)+1,y+13);
   end;
   if TYPE(item) == 0 then
      if (item MOD 100) > 20 OR (item MOD 100) < 4 then
         value:=EXPR(RIGHT(STRING(item),1));
         t2:=IFTE(value == 1 OR value == 2 OR value == 3,th(value),"th");
      end;
      case
      if item == 1 then txt:=t1+STRING(item)+t2+" hand "; end;
      if item == SIZE(PHAND) then txt:=t1+"last hand ";end;
      txt:=t1+STRING(item)+t2+t3;
      end;
   else
      txt:=" "+item+" ";
   end;
   lastx(1):=TEXTOUT_P(txt,G2,0,0,2);
   TEXTOUT_P(txt,x,y,2,black,200,card_front);
end;


settle_ins(hand)
begin
   if DSTATE(STATE_BJ) then
      PSTATUS("Insurance Won $"+STRING(PSTATE(hand,STATE_INS)*2,6,2,0),2);
      money(MONEY_BANK):=money(MONEY_BANK)+PSTATE(hand,STATE_INS)*2;
      stat(STAT_INSWON):=stat(STAT_INSWON)+1;
      PSTATE(hand,STATE_RESULT):=2*PSTATE(hand,STATE_INS)/money(MONEY_BET);
   else
      PSTATUS("Insurance Lost $"+STRING(PSTATE(hand,STATE_INS),6,2,0),2);
      money(MONEY_BANK):=money(MONEY_BANK)-PSTATE(hand,STATE_INS);
      stat(STAT_INSLOST):=stat(STAT_INSLOST)+1;
      PSTATE(hand,STATE_RESULT):=-PSTATE(hand,STATE_INS)/money(MONEY_BET);
   end;
   data_collect(hand);
end;


END_ROUND()
begin
   local i,j,k,hand,var:={DHAND,PHAND};

   if NOT empty_deck_shuffle then PSTATUS("",3); end;
   orig_bank:=money(MONEY_BANK);
   orig_bet:=money(MONEY_BET);

   case
   if SIZE(PHAND) > 1 AND NOT ace_split then summary(); end;
   bj_result(1); if ace_split then bj_result(2); end;
   end;

   if auto_bet then do_auto_bet(); end;
   disp_result();

   otto:=(otto AND GETKEY() <> 30);

   for j from 1 to SIZE(var) do
      hand:=var(j);
      for k from 1 to SIZE(hand) do
         for i from 1 to SIZE(hand(k)) do
            DISC:=CONCAT(DISC,hand(k,i,1));
         end;
      end;
   end;
   DHAND:={}; PHAND:={};
end;


data_collect(hand)
begin
   local start,end;
   if stat_collect <> 1 then
      D1:=CONCAT(D1,money(MONEY_BANK));
      D2:=CONCAT(D2,PSTATE(hand,STATE_TC));
      D3:=CONCAT(D3,PSTATE(hand,STATE_RESULT));
      end:=SIZE(D1);
      if end > stat_collect_val(stat_collect) then
         start:=end-stat_collect_val(stat_collect)+1;
         D1:=SUB(D1,start,end); D2:=SUB(D2,start,end); D3:=SUB(D3,start,end);
      end;
   end;
end;


desktop_color()
begin
   local red:=RANDINT(180,210),green:=RANDINT(190,230),blue:=RANDINT(195,225);
   desktop:=RGB(red,green,blue);
   card_back:=RGB(IFTE(red+10>255,255,red+10),IFTE(green+15>255,255,green+15),IFTE(blue+15>255,255,blue+15));
   moon:=IFTE(green+15 < 210 OR blue+15 < 210 OR red+10 < 195,1,0);
   grad1:={RGB(RANDINT(100,200),RANDINT(100,200),RANDINT(100,200)),RANDINT(185,200)};
   grad2:={RGB(RANDINT(100,200),RANDINT(100,200),RANDINT(100,200)),RANDINT(185,200)};
end;


INTERMISSION()
begin
   local what,i;
   BLIT_P(G5,G1,LART(13,1),LART(13,2),LART(13,3),LART(13,4));
   BLIT_P(G9,G1,LART(14,1),LART(14,2),LART(14,3),LART(14,4));

   repeat
      what:=GETACT("inter",{saved});
      case
      if what == CMD_STAT then
         DIMGROB_P(G2,dx+1,dy+1);
         PSTATUS("",4);
         BLIT_P(G2,G0);
         final_stats();
         BLIT_P(G0,G2);
      end;
      if what == CMD_GAME then
         game_save();
         PSTATUS("Game saved.",4);
      end;
      if what == CMD_PREF then
         pref_save();
         PSTATUS("Preferences saved.",4);
      end;
      if what == CMD_BET then
         DIMGROB_P(G2,dx+1,soft_dy+1);
         PSTATUS("",4);
         BLIT_P(G2,G0);
         BET();
         if orig_deck <> ndeck then MAKEDECK(); continue; end;
         BLIT_P(G0,G2);
         CLSTAT();
         for i from 1 to SIZE(last_pstatus) do
            PSTATUS(last_pstatus(i),i);
         end;
      end;
      end;
   until what == CMD_QUIT OR what == CMD_DEAL;
   return what;
end;


init_gvars()
begin
   dark:=(Theme(1) == #2h);
   cardcount:=0; ndeck:=1; orig_deck:=0; unseen:=0;
   show_hint:=0; auto_bet:=0; meter:=0;
   money:=[pbet,pbank,pminbet,pmaxbet];
   pref_money:=money; devi:=0;
   orig_bet:=money(MONEY_BET);
   orig_bank:=money(MONEY_BANK);
   stat:=[0,0,0,0,0,0,0,0,0,0,0];

   otto:=0;
   otto_wait_val:=[2.5,1.0,0.2,0];
   stat_collect_val:=[0,50,100,200];
   stat_collect:=1;
   BS_adv:=0;

   SDECK:={}; DISC:={}; DHAND:={}; PHAND:={};
   seen:=0; ccount:=0; offer_ins:=0; cut_card:=0; true_count:=0;
   strat_follow:=0; strat_total:=0; rounds:=0; deck_rounds:=0;
   empty_deck_shuffle:=0; dealer_card_seen:=0; moon:=0;
   location:=[1,1];
   show_bet:=0;
   SUIT:={CHAR(9824),CHAR(9829),CHAR(9830),CHAR(9827)};
   lastx:=[0,0,0,0,0,0,0,0,0,0];
   saved:=[0,0];
   bad_bet:=0; bad_ins:=0;
end;

pref_save()
begin
   BLKJKpref:={pref_money,unseen,show_hint,auto_bet,meter,ndeck,
      stat_collect,show_bet,BS_adv,cardcount,card_back,desktop,moon,grad1,grad2};
   saved(2):=1;
end;

pref_load()
begin
   pref_money:=BLKJKpref(1);
   unseen:=BLKJKpref(2);
   show_hint:=BLKJKpref(3);
   auto_bet:=BLKJKpref(4);
   meter:=BLKJKpref(5);
   ndeck:=BLKJKpref(6);
   stat_collect:=BLKJKpref(7);
   show_bet:=BLKJKpref(8);
   BS_adv:=BLKJKpref(9);
   cardcount:=BLKJKpref(10);
   card_back:=BLKJKpref(11);
   desktop:=BLKJKpref(12);
   moon:=BLKJKpref(13);
   grad1:=BLKJKpref(14);
   grad2:=BLKJKpref(15);
   money:=pref_money;
   saved(2):=1;
end;

game_save()
begin
   BLKJKsave:={SDECK,DISC,DSTATE,PSTATE,money,stat,rounds,deck_rounds,
      ccount,offer_ins,cut_card,true_count,strat_follow,strat_total,
      seen,unseen,show_hint,auto_bet,meter,ndeck,cardcount,
      stat_collect,empty_deck_shuffle,dealer_card_seen,orig_deck,show_bet,BS_adv};
   BLKJKdata:=IFTE(stat_collect <> 1,{D1,D2,D3},0);
   saved(1):=1;
end;


game_load()
begin
   SDECK:=BLKJKsave(1);
   DISC:=BLKJKsave(2);
   DSTATE:=BLKJKsave(3);
   PSTATE:=BLKJKsave(4);
   money:=BLKJKsave(5);
   stat:=BLKJKsave(6);
   rounds:=BLKJKsave(7);
   deck_rounds:=BLKJKsave(8);
   ccount:=BLKJKsave(9);
   offer_ins:=BLKJKsave(10);
   cut_card:=BLKJKsave(11);
   true_count:=BLKJKsave(12);
   strat_follow:=BLKJKsave(13);
   strat_total:=BLKJKsave(14);
   seen:=BLKJKsave(15);
   unseen:=BLKJKsave(16);
   show_hint:=BLKJKsave(17);
   auto_bet:=BLKJKsave(18);
   meter:=BLKJKsave(19);
   ndeck:=BLKJKsave(20);
   cardcount:=BLKJKsave(21);
   stat_collect:=BLKJKsave(22);
   empty_deck_shuffle:=BLKJKsave(23);
   dealer_card_seen:=BLKJKsave(24);
   orig_deck:=BLKJKsave(25);
   show_bet:=BLKJKsave(26);
   BS_adv:=BLKJKsave(27);
   if stat_collect <> 1 AND TYPE(BLKJKdata) == 6 AND SIZE(BLKJKdata) == 3 then
      D1:=BLKJKdata(1); D2:=BLKJKdata(2); D3:=BLKJKdata(3);
   end;
   orig_bet:=money(MONEY_BET);
   saved:=[1,0];
end;


disp_result()
begin
   local res_str,delta:=money(MONEY_BANK)-orig_bank;
   res_str:="$"+STRING(ABS(delta),6,2,0);
   case
   if delta > 0 then res_str:="Won "+res_str; end;
   if delta < 0 then res_str:="Lost "+res_str; end;
   res_str:="Push";
   end;
   PSTATUS(IFTE(SIZE(PHAND)>1,"Split ","")+res_str,1);
end;


disp_bank_bet(force)
begin
   local x:=dx-2,y:=STATUSY-3,i,yoff:=12;
   local str,val;

   if NOT show_bet AND NOT force then return; end;

   val:={IFTE(force,10000,money(MONEY_BANK)),IFTE(force,10,money(MONEY_BET))};
   for i from 1 to 2 do
      if lastx(i+1) <> 0 then
         RECT_P(x-lastx(i+1),y-3,dx,y+9,statusarea);
      end;
      str:="$"+STRING(val(i),6,2,0);
      lastx(i+1):=TEXTOUT_P(str,G2,0,0,1);
      TEXTOUT_P(str,x-lastx(i+1),y,1,IFTE(i == 2 AND orig_bet <> money(MONEY_BET) AND auto_bet AND NOT force,red,black));
      y:=y+yoff;
   end;
end;


init_format()
begin
   orig_HFormat:=HFormat; orig_HAngle:=HAngle;
   orig_AAngle:=AAngle; orig_AFormat:=AFormat;
   HFormat:=0; HAngle:=1;
   AAngle:=0; AFormat:=0;
end;


restore_format()
begin
   HFormat:=orig_HFormat; HAngle:=orig_HAngle;
   AAngle:=orig_AAngle; AFormat:=orig_AFormat;
end;


welcome_header()
begin
   draw_bit_art("welcome",0);
   BLIT_P(G0,50,65,80+GROBW_P(G4)*1,65+GROBH_P(G4)*2,G4,nocolor);
   TEXTOUT_P("Blackjack by Du"+CHAR(353)+"an, 2025",47,95,1,black);
   TEXTOUT_P("Windsor, CO",79,110,1,black);
   DRAWCARD({RANDINT(1,4)*13-12,0},[2,11],1,0,0);
   DRAWCARD({0,card_offset(RANDINT(1,SIZE(card_offset)))},[2,12],1,0,0);
end;


welcome()
begin
   local what,load,loaded:=0,page:=1;

   load:=IFTE(TYPE(BLKJKsave) == 6 AND SIZE(BLKJKsave) == 27,1,0);
   copy_desktop();
   welcome_header();
   help(1,saved(2));

   repeat
      what:=GETACT("welcome",{load});
      case
      if load AND what == CMD_LOAD then
         CLSTAT(); game_load(); loaded:=1; load:=0;
         PSTATUS("Game loaded.",1);
      end;
      if what == CMD_COLOR then
         DRAWMENU(""); desktop_color(); desktop_art(); copy_desktop(); welcome_header(); help(page,0); saved(2):=0;
      end;
      if what == CMD_HELP then
         page:=IFTE(page == 5,1,page+1);
         help(page,0);
      end;
      end;
   until what == CMD_PLAY OR what == CMD_QUIT;

   if what == CMD_PLAY AND NOT loaded AND stat_collect <> 1 then
      D1:={};D2:={};D3:={};
   end;
   return what;
end;


help(page,pref)
begin
   local x:=STATUSX,y:=STATUSY,yoff:=16;
   CLSTAT();
   case
   if page == 1 then
      if pref then TEXTOUT_P("(Preferences loaded)",220,y,1,black); end;
      TEXTOUT_P("Getting started:",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ There are multiple pages for Bet input; page 2 contains Settings.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ During Auto Mode, press [Enter] to cancel; wait for end of round.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ First row of white keys and [Enter] act as soft keys.",x,y,1,black); y:=y+yoff;
   end;
   if page == 2 then
      TEXTOUT_P("Table rules (Vegas rules variation):",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ Restricted Ace split ✓ Blackjack pays 3:2 ✓ Insurance pays 2:1.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ Dealer stands on soft 17 ✓ Double-down after split allowed.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ Late surrender available ✓ No Blackjack during split.",x,y,1,black); y:=y+yoff;
   end;
   if page == 3 then
      otto_icon(1); disp_bank_bet(1); disp_card_count(1);
      TEXTOUT_P("Displayable options available in 'Settings':",x,y,1,black); y:=y+yoff;
      TEXTOUT_P(CHAR(9312)+" Current Bank and Bet",x,y,1,black); y:=y+yoff; TEXTOUT_P(CHAR(9312),246,STATUSY+3,2,black);
      TEXTOUT_P(CHAR(9313)+" Card Count, True Count, Unseen Cards",x,y,1,black); y:=y+yoff; TEXTOUT_P(CHAR(9313),246,STATUSY+25,2,black);
      TEXTOUT_P(CHAR(9314)+" Auto Mode, BS Deviate, Collect Data, Auto Bet",x,y,1,black); y:=y+yoff; TEXTOUT_P(CHAR(9314),246,STATUSY+47,2,black);
   end;
   if page == 4 then
      TEXTOUT_P("Basic Strategy related settings:",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ 'Auto Bet' uses the True Count to calculate the 'ideal' bet.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ 'Show Hint' highlights Basic Strategy actions for your hand.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ 'BS Deviate' alters Basic Strategy by utilizing the True Count.",x,y,1,black); y:=y+yoff;
   end;
   if page == 5 then
      TEXTOUT_P("Game save and 'Settings' preferences:",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ 'Save GAME' saves your game and Settings.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ 'Save PREF' saves Settings & colors; they're then loaded at startup.",x,y,1,black); y:=y+yoff;
      TEXTOUT_P("✓ Loading a saved game will overwrite preference Settings.",x,y,1,black); y:=y+yoff;
   end;
   end;
end;


disp_meter()
begin
   local w:=4;
   local x:=dx-w,y:=STATUSY-7,calc,calc_plastic;
   BLIT_P(x,0,G3,x,0,x+w+1,y+1);
   if meter then
      max_dx:=x;
      calc_plastic:=y*cut_card/(ndeck*52);
      calc:=y*(SIZE(SDECK)/(ndeck*52));

      RECT_P(x,y,x+w,y-calc,black,IFTE(calc <= calc_plastic,mag,statusarea));
      if calc_plastic < calc then
         RECT_P(x,y-calc_plastic,x+w,y,black,mag);
      end;
   else
      max_dx:=dx;
   end;
end;


shuffle_msg()
begin
   case
   if empty_deck_shuffle then
      PSTATUS("Empty deck. Discard pile is in use.",3);
   end;
   if SIZE(SDECK) <= cut_card AND NOT offer_ins then
      PSTATUS("Shuffle cut card visible.",3);
   end;
   end;
end;


copy_desktop()
begin
   BLIT_P(G0,G3);
   lastx:=[0,0,0,0,0,0,0,0,0,0];
   last_pstatus:={"","","",""};
end;


desktop_art()
begin
   local i,var,prev_x,x,str:="sun";
   local xs,ss,y:=0;
   LART:={};

   DIMGROB_P(G3,dx+1,soft_dy+1,desktop);
   DIMGROB_P(G2,160,20);
   DIMGROB_P(G1,685,50); //stored art
   DIMGROB_P(G5,52,21);
   DIMGROB_P(G9,52,21);

   RECT_P(G3,0,STATUSY-7,dx,soft_dy,statusarea);
   RECT_P(G3,0,STATUSY-6,dx,STATUSY-25,grad1);
   RECT_P(G3,0,STATUSY-26,dx,STATUSY-29,grad2);

   draw_bit_art("line",0);
   BLIT_P(G3,0,STATUSY-9,dx,STATUSY-9+GROBH_P(G4),G4,nocolor);
   LINE_P(G3,0,STATUSY-7,dx,STATUSY-7,black);

   if moon then str:="moon"; y:=10; end;
   x:=RANDINT(70,250);
   draw_bit_art(str,0);
   BLIT_P(G3,x,y,x+GROBW_P(G4)*1.2,y+GROBH_P(G4)*2,G4,nocolor);

   for i from 1 to RANDINT(1,3) do
      x:=RANDINT(70,250);
      draw_bit_art("cloud",0);
      BLIT_P(G3,x,0,x+GROBW_P(G4)*RANDOM(1.8,2.5),0+GROBH_P(G4)*RANDOM(0.5,2.5),G4,0,0,GROBW_P(G4),GROBH_P(G4),nocolor,RANDINT(180,245));
   end;

   xs:={0.5,0.6,0.7,0.5,0.6,0.7};
   for i from 1 to RANDINT(2,3) do
      draw_bit_art("bug",0);
      ss:=RANDINT(1,SIZE(xs));
      x:=RANDINT(70,305);
      y:=RANDINT(0,STATUSY-32-CEILING(GROBH_P(G4)*xs(ss)*2));
      BLIT_P(G3,x,y,x+GROBW_P(G4)*xs(ss),y+GROBH_P(G4)*xs(ss)*1.5,G4,nocolor);
   end;

   var:={{"card",card_back},{"card",card_front},{"otto",0},{"hint",card_back},{"save",#202020h},{"Hit",0},{"Stand",0},
      {"DBL",0},{"Split",0},{"Yes",0},{"No",0},{"Surr",0},{"GAME",0},{"PREF",0}};

   for i from 1 to SIZE(var) do
      draw_bit_art(var(i,1),var(i,2));
      prev_x:=IFTE(i > 1,LART(i-1,3),0);
      LART(i):={prev_x,0,prev_x+GROBW_P(G4),GROBH_P(G4),GROBW_P(G4),GROBH_P(G4)};
      BLIT_P(G1,LART(i,1),LART(i,2),LART(i,3),LART(i,4),G4);
   end;

   //veg
   x:={RANDINT(265,290),RANDINT(240,255)};
   if (RANDINT(1,6) MOD 2) then var:=REVERSE(var); end;
   draw_bit_art("thisle",0);
   BLIT_P(G3,x(1),109,x(1)+GROBW_P(G4)*2,109+GROBH_P(G4)*2,G4,nocolor);
   draw_bit_art("thisle",0);
   BLIT_P(G3,x(2),119,x(2)+GROBW_P(G4)*1.5,119+GROBH_P(G4)*1.5,G4,nocolor);

   //thisle on card
   BLIT_P(G1,LART(2,1)+19,LART(2,2)+9,LART(2,1)+19+12,LART(2,2)+9+24,G4,nocolor);
   for i from 1 to RANDINT(1,2) do
      draw_bit_art("grass",0);
      x:=RANDINT(70,230);
      BLIT_P(G3,x,138,x+GROBW_P(G4),138+GROBH_P(G4),G4,nocolor);
   end;

   //hole card
   draw_bit_art("back",0);
   BLIT_P(G1,LART(1,1)+1,LART(1,2)+1,LART(1,1)+1+32,LART(1,2)+1+45,G4,nocolor);
end;


basic_strat_stats(key,hint)
begin
   strat_total:=strat_total+1;
   if key == hint then strat_follow:=strat_follow+1; end;
end;


otto_icon(force)
begin
   local yd,ys,ya,yo:=197;
   local disp:={0,0,0,0},flags,i,j:=0;
   local xm:=[[302,284,275,265],[310,293,283,0],[310,293,0,0],[304,0,0,0]];

   case
   if force then end;
   if NOT show_bet AND NOT cardcount AND NOT unseen then yo:=STATUSY-5; end;
   if NOT show_bet then yo:=STATUSY+18; end;
   if NOT cardcount AND NOT unseen then yo:=STATUSY+20; end;
   end;
   ys:=yo+5; yd:=ys; ya:=yo+6;

   flags:=IFTE(force,{1,1,1,1},{(otto <> 0),BS_adv,(stat_collect <> 1),auto_bet});
   for i from 4 downto 1 do
      if flags(i) then
         j:=j+1;
         disp(i):=xm(i,j);
      end;
   end;

   case
   if otto AND BS_adv AND stat_collect <> 1 AND ΣLIST(flags) == 3 then
      disp(1):=disp(1)+6; disp(2):=disp(2)+7;
   end;
   if BS_adv AND stat_collect <> 1 AND ΣLIST(flags) == 2 then
      disp(2):=disp(2)+7;
   end;
   if otto AND (stat_collect <> 1 OR BS_adv) AND ΣLIST(flags) == 2 then
      disp(1):=disp(1)+7;
   end;
   end;

   if disp(1) then
      lastx(10):=disp(1);
      BLIT_P(disp(1),yo,disp(1)+LART(3,5)*1.25*0.3,yo+LART(3,6)*1.25,G1,LART(3,1),LART(3,2),LART(3,3),LART(3,4),nocolor);
   end;
   if disp(2) then
      TEXTOUT_P(CHAR(948),disp(2),yd,2,IFTE(devi,red,black),20,statusarea);
      devi:=0;
   end;
   if disp(3) then
      TEXTOUT_P(CHAR(931),disp(3),ys,2,black,20,statusarea);
   end;
   if disp(4) then
      TEXTOUT_P("ab",disp(4),ya,1,IFTE(orig_bet <> money(MONEY_BET) AND NOT force,red,black),20,statusarea);
      ARC_P(disp(4)+5,ya+4,7,IFTE(orig_bet <> money(MONEY_BET) AND NOT force,red,linecolor));
   end;

   if NOT otto AND lastx(10) AND NOT force then
      RECT_P(lastx(10),yo,lastx(10)+LART(3,5)*1.25*0.3,yo+LART(3,6)*1.25,statusarea);
      lastx(10):=0;
   end;
end;


setup_hint(hint)
begin
   local x;
   case
   if NOT show_hint AND NOT otto then return; end;
   if offer_ins then x:=IFTE(hint == CMD_YES,5,6); end;
   if hint == CMD_HIT then x:=1; end;
   if hint == CMD_STAND then x:=2; end;
   if hint == CMD_DBL then x:=3; end;
   if hint == CMD_SPLIT then x:=4; end;
   if hint == CMD_SURR then x:=7; end;
   end;
   BLIT_P(G5,G1,LART(x+5,1),LART(x+5,2),LART(x+5,3),LART(x+5,4));
end;


init_strat()
begin
   local h:=CMD_HIT,s:=CMD_STAND;
   local d:=CMD_DBL_HIT,Q:=CMD_SPLIT;
   local X:=CMD_SURR,Z:=CMD_DBL_STAND;
   local n:=CMD_NONE,N:=CMD_NEG,P:=CMD_POS;

   bstrat:={
{h,h,h,h,h,h,h,h,h,h},
{h,h,h,h,h,h,h,h,h,h},
{h,h,h,h,h,h,h,h,h,h},
{h,h,h,h,{h,2,d},h,h,h,h,h},
{{h,1,d},d,d,d,d,{h,3,d},h,h,h,h},
{d,d,d,d,d,d,d,d,{h,4,d},{h,4,d}},
{d,d,d,d,d,d,d,d,d,{h,1,d}},
{{h,3,s},{h,2,s},{s,N,h},s,s,h,h,h,h,h},
{{s,-1,h},s,s,s,s,h,h,h,h,h},
{s,s,s,s,s,h,h,h,h,h},
{s,s,s,s,s,h,h,h,{h,4,s},h},
{s,s,s,s,s,h,h,{h,4,s},{h,P,s},h},
{s,s,s,s,s,s,s,s,s,s},
{s,s,s,s,s,s,s,s,s,s},
{s,s,s,s,s,s,s,s,s,s},
{s,s,s,s,s,s,s,s,s,s},

{h,h,h,d,d,h,h,h,h,h},
{h,h,h,d,d,h,h,h,h,h},
{h,h,d,d,d,h,h,h,h,h},
{h,h,d,d,d,h,h,h,h,h},
{{h,1,d},d,d,d,d,h,h,h,h,h},
{Z,Z,Z,Z,Z,s,s,h,h,h},
{s,s,{s,3,Z},{s,1,Z},{Z,1,s},s,s,s,s,s},
{s,s,s,s,s,s,s,s,s,s},

{Q,Q,Q,Q,Q,Q,n,n,n,n},
{Q,Q,Q,Q,Q,Q,n,n,n,n},
{n,n,n,Q,Q,n,n,n,n,n},
{n,n,n,n,n,n,n,n,n,n},
{Q,Q,Q,Q,Q,n,n,n,n,n},
{Q,Q,Q,Q,Q,Q,n,n,n,n},
{Q,Q,Q,Q,Q,Q,Q,Q,Q,Q},
{Q,Q,Q,Q,Q,n,Q,Q,n,n},
{n,n,{n,6,Q},{n,5,Q},{n,4,Q},n,n,n,n,n},
{Q,Q,Q,Q,Q,Q,Q,Q,Q,Q},

{n,n,n,n,n,n,n,{n,2,X},{X,N,n},{n,2,X}},
{n,n,n,n,n,n,{n,4,X},{X,-1,n},X,X}};
end;


bstrat_mod(val)
begin
   local ret:=val;
   if TYPE(val) == 6 then
      case
      if NOT BS_adv then return val(1); end;
      if val(2) == CMD_NEG then ret:=IFTE(true_count < 0,val(3),val(1)); end;
      if val(2) == CMD_POS then ret:=IFTE(true_count > 0,val(3),val(1)); end;
      if val(2) > 0 then ret:=IFTE(true_count >= val(2),val(3),val(1)); end;
      if val(2) < 0 then ret:=IFTE(true_count <= val(2),val(3),val(1)); end;
      ret:=val(1);
      end;
      if ret <> val(1) then devi:=val(1); end;
   end;
   return ret;
end;


basic_strat(hand)
begin
   local c1,c2,ptot,soft,dc1,res;

   c1:=CARDVAL(PHAND(hand,1));
   c2:=CARDVAL(PHAND(hand,2));
   ptot:=PSTATE(hand,STATE_TOT);
   soft:=PSTATE(hand,STATE_ACE);
   dc1:=CARDVAL(DHAND(1,1))-1;

   case
   if offer_ins then
      res:=IFTE(BS_adv AND true_count >= 3 AND NOT PSTATE(hand,STATE_BJ),CMD_YES,CMD_NO);
   end;
   if ptot > 20 then
      res:=CMD_STAND;
   end;
   if c1 == c2 AND SIZE(PHAND(hand)) == 2 then
      res:=bstrat_mod(bstrat(c1+23,dc1));
      if res == CMD_NONE then
         res:=IFTE(ptot > 4,bstrat_mod(bstrat(ptot-4,dc1)),CMD_HIT);
      end;
   end;
   if soft AND ptot <= 20 AND ptot >= 13 then
      res:=bstrat_mod(bstrat(ptot+4,dc1));
   end;
   if (ptot == 15 OR ptot == 16) AND SIZE(PHAND(hand)) == 2 then
      res:=bstrat_mod(bstrat(ptot+20,dc1));
      if res == CMD_NONE then
         res:=bstrat_mod(bstrat(ptot-4,dc1));
      end;
   end;
   if ptot > 4 then
      res:=bstrat_mod(bstrat(ptot-4,dc1));
   end;
   res:=CMD_HIT;
   end;

   if SIZE(PHAND(hand)) > 2 then
      case
      if res == CMD_DBL_HIT then res:=CMD_HIT; end;
      if res == CMD_DBL_STAND then res:=CMD_STAND; end;
      end;
      case
      if NOT BS_adv then end;
      if devi == CMD_DBL_HIT then devi:=CMD_HIT; end;
      if devi == CMD_DBL_STAND then devi:=CMD_STAND; end;
      end;
   else
      if res == CMD_DBL_HIT OR res == CMD_DBL_STAND then res:=CMD_DBL; end;
      if BS_adv AND (devi == CMD_DBL_HIT OR devi == CMD_DBL_STAND) then devi:=CMD_DBL; end;
   end;
   if BS_adv AND res == devi then devi:=0; end;
   return res;
end;


get_ins(hand)
begin
   local what,res,ins_amount,hint:=basic_strat(hand);

   repeat
      PSTATUS("Insurance?",2);
      what:=GETACT("ins",{hint});
   until what == CMD_YES OR what == CMD_NO;

   PSTATUS("",2);
   offer_ins:=0;

   if what == CMD_YES then
      ins_amount:=ROUND(money(MONEY_BET)/2,2);

      if NOT otto then
         DIMGROB_P(G2,dx+1,dy+1);
         BLIT_P(G2,G0);
         res:=INPUT({{ins_amount,[0],{45,25,2}}},"Insurance Side Bet","Insurance Bet ","Maximum is "+CHAR(189)+" your hand bet.");
         BLIT_P(G0,G2);

         if NOT res OR ins_amount <= 0 then
            bad_ins:=1; what:=CMD_NO;
         else
            if ins_amount > ROUND(money(MONEY_BET)/2,2) then
               ins_amount:=ROUND(money(MONEY_BET)/2,2);
            end;
         end;
      end;
      if NOT bad_ins then PSTATE(hand,STATE_INS):=ROUND(ins_amount,2); end;
   end;
   basic_strat_stats(what,hint);
end;


disp_card_count(force)
begin
   local y:=177,x:=190;
   local s_cc,s_un,s_32;
   local p_cc,p_un,p_sp,p_32;
   local color:=statusarea;

   if NOT cardcount AND NOT unseen AND NOT force then return; end;
   if NOT show_bet AND NOT force then y:=STATUSY-2; end;

   s_cc:=IFTE(force,0,ccount)+", "+STRING(IFTE(force,0,true_count),6,1,0);
   s_un:=IFTE(force,52,(ndeck*52)-seen);
   s_32:=" ";

   p_cc:=TEXTOUT_P(s_cc,G2,0,0,2);
   p_un:=TEXTOUT_P(s_un,G2,0,0,2);
   p_sp:=TEXTOUT_P(", ",G2,0,0,2);
   p_32:=TEXTOUT_P(s_32,G2,0,0,2);

   case
   if cardcount AND unseen OR force then x:=dx-4-p_cc-p_un-p_sp; end;
   if cardcount then x:=dx-4-p_cc; end;
   if unseen then x:=dx-4-p_un; end;
   end;

   if lastx(4) <> 0 then
      RECT_P(lastx(4),y,dx-2,y+17,color);
   end;
   RECT_P(x-3,y,dx-2,y+17,linecolor,card_front);
   lastx(4):=x-3;

   case
   if cardcount AND unseen OR force then
      TEXTOUT_P(s_cc,x,y+3,2,IFTE(ccount < 0 AND NOT force,red,black));
      TEXTOUT_P("  "+s_un,x+p_cc,y+3,2,black);
      LINE_P(dx-4-p_un-p_32,y,dx-4-p_un-p_32,y+17,linecolor);
   end;
   if cardcount then
      TEXTOUT_P(s_cc,x,y+3,2,IFTE(ccount < 0 AND NOT force,red,black));
   end;
   if unseen then
      TEXTOUT_P(s_un,x,y+3,2,black);
   end;
   end;
end;


final_stats()
begin
   local y:=22,yoff:=15,ys,xs,i;
   local x:=180,x1:=33,y1;
   local what,follow,x2:=x-3,x3:=34;

   RECT_P(0,0,dx,y-1,desktop);
   RECT_P(0,y-1,dx,soft_dy,card_front);

   ys:=MAKELIST(xs,xs,y-2,200,yoff); ys:=CONCAT(ys,{soft_dy});
   xs:={0,x2,0,x2,x1,x-x3,0,x2,x1,x-x3,0,x2,0,dx+1};
   for i from 1 to SIZE(xs) step 2 do
      RECT_P(xs(i),ys(i)+1,xs(i+1)-1,ys(i+1)-1,card_back);
   end;
   xs:={0,0,0,0,x1,x1,0,0,x1,x1,0,0,0};
   for i from 1 to SIZE(xs) do
      LINE_P(xs(i),ys(i),dx,ys(i),linecolor);
   end;
   y1:={{4,7},{8,11},{4,7},{8,11},{1,4},{7,8},{11,13}};
   xs:={{x1,x1},{x1,x1},{x-x3,x-x3},{x-x3,x-x3},{x2,x2},{x2,x2},{x2,x2}};
   for i from 1 to SIZE(xs) do
      LINE_P(xs(i,1),ys(y1(i,1)),xs(i,2),ys(y1(i,2)),linecolor);
   end;

   TEXTOUT_P("Game Stats",129,4,2,black);

   TEXTOUT_P("Current Bank",5,ys(1)+2,2,black);
   TEXTOUT_P("$",x-11,ys(1)+2,2,black);
   TEXTOUT_P(STRING(money(MONEY_BANK),6,2,0),x,ys(1)+2,2,black);

   TEXTOUT_P("Rounds + Splits",5,ys(2)+2,2,black);
   TEXTOUT_P(STRING(rounds,1,0,0)+" + "+STRING(stat(STAT_SPLIT),1,0,0),x,ys(2)+2,2,black);

   y1:={{"Wins",STAT_WIN,ys(3),0,0,1},{"Losses",STAT_LOSE,ys(7),0,0,1},{"Surrenders",STAT_SURR,ys(11),0,0,1},{"Pushes",STAT_TIE,ys(12),0,0,1},
       {"Naturals",STAT_BJ,ys(4),32,31,1},{"Busts",STAT_BUST,ys(8),32,31,1},
       {"Insurance wins",STAT_INSWON,ys(5),32,31,0},{"Double down wins",STAT_DBLWIN,ys(6),32,31,0},{"Insurance losses",STAT_INSLOST,ys(9),32,31,0},
       {"Double down losses",STAT_DBLLOSS,ys(10),32,31,0}};

   for i from 1 to SIZE(y1) do
      if y1(i,6) then stat_pcent(y1(i,3)+2,rounds+stat(STAT_SPLIT),y1(i,2),IFTE(y1(i,4),1,2)); end;
      TEXTOUT_P(y1(i,1),5+y1(i,4),y1(i,3)+2,2,black);
      TEXTOUT_P(stat(y1(i,2)),x-y1(i,5),y1(i,3)+2,2,black);
   end;

   follow:=IFTE(strat_total == 0,0,%TOTAL(strat_total,strat_follow));
   TEXTOUT_P("Basic Strategy "+IFTE(BS_adv,CHAR(948)+" ","")+"followed  "+STRING(follow,6,1)+"%  of the time.",5+32,ys(13)+2+2,2,black);

   repeat
      what:=GETACT("stats",{});
      if what == CMD_DECK OR what == CMD_DISC then
         DIMGROB_P(G7,dx+1,soft_dy+1);
         BLIT_P(G7,G0);
         Plot(what,(ndeck*52)-seen);
         while GETACT("back",{}) <> 6 do end;
         BLIT_P(G0,G7);
      end;
   until what == CMD_CONT;
end;


stat_pcent(y,tot,val,font)
begin
   local str,xn;
   str:=IFTE(tot == 0,"0",STRING(%TOTAL(tot,stat(val)),6,1,0))+"%";
   xn:=TEXTOUT_P(str,G7,0,0,font);
   if font == 2 then RECT_P(dx-xn-3,y-1,dx,y+12,card_back); end;
   TEXTOUT_P(str,dx-xn,y+IFTE(font==1,2,0),font,black);
   LINE_P(dx-xn-3,y-1,dx-xn-3,y+13,linecolor);
end;


do_auto_bet()
begin
   local minbet,maxbet,new_bet;
   minbet:=money(MONEY_MIN);
   maxbet:=money(MONEY_MAX);

   if shuffle() then
      money(MONEY_BET):=minbet;
   else
      new_bet:=CEILING(true_count)*minbet;
      if new_bet > 0 AND new_bet > minbet then
         if new_bet > maxbet then new_bet:=maxbet; end;
         money(MONEY_BET):=ROUND(new_bet,2);
      else
         money(MONEY_BET):=minbet;
      end;
   end;
end;


BET()
begin
   local bet:=money(MONEY_BET),bank:=money(MONEY_BANK);
   local minbet:=money(MONEY_MIN),maxbet:=money(MONEY_MAX);
   local pref_bet:=pref_money(MONEY_BET),pref_bank:=pref_money(MONEY_BANK);
   local pref_minbet:=pref_money(MONEY_MIN),pref_maxbet:=pref_money(MONEY_MAX);
   local res,post,pre,pref_post,pref_pre;
   otto:=1;

   pre:={auto_bet,show_bet,show_hint,BS_adv,ndeck,stat_collect,meter,cardcount,unseen};
   pref_pre:={pref_bet,pref_bank,pref_minbet,pref_maxbet};

   res:=INPUT({{bet,[0],{25,18,1}},{bank,[0],{65,30,1}},{minbet,[0],{25,18,3}},{maxbet,[0],{65,30,3}},
    {auto_bet,0,{25,10,4}},{show_bet,0,{25,10,5}},{otto,{"Off","Slow","Med","Fast","Turbo"},{50,20,8}},
    {show_hint,0,{40,20,10}},{BS_adv,0,{40,20,11}},
    {ndeck,{"1","2","3","4","5","6","7","8"},{25,20,9}},
    {meter,0,{80,10,9}},{cardcount,0,{80,10,10}},{unseen,0,{80,10,11}},
    {stat_collect,{"None","50","100","200"},{65,20,12}},
    {pref_bet,[0],{25,18,15}},{pref_bank,[0],{25,30,16}},{pref_minbet,[0],{25,18,18}},{pref_maxbet,[0],{25,30,19}}},
   {"Bet for Round "+STRING(rounds+1,6,0,0),"Settings","Starting Bet Preferences"},
   {"Bet ","Bank ","Min Bet ","Max Bet ","Auto Bet ","Show Bet ","Auto Mode ","Show Hint ","BS Deviate ",
    "Decks ","Show Graph ","Show Count ","Show Unseen ","Rows of Data to Collect ","Bet ","Bank ","Min Bet ","Max Bet "},
   {"Enter your bet amount for the next round.","Enter your total cash on hand.","Minimum bet for Auto Bet.",
    "Maximum bet for Auto Bet.","Adjust bet based on True Count?","View Bank and Bet in status area?",
    "Automate rounds? (Press [Enter] to stop.)","Suggest Basic Strategy actions?",
    "Alter Basic Strategy using True Count?","Choose the number of decks in play.",
    "View bar graph of deck with shuffle cut card?","View Card Count, True Count?",
    "View Unseen Card count?","Collect Bank, True Count, Result in D1, D2, D3.",
    "Preferred starting Bet.","Preferred starting cash on hand.","Preferred starting minimum Auto Bet.",
    "Preferred starting maximum Auto Bet."});

   if bet <= 0 OR minbet <= 0 OR maxbet < minbet then bad_bet:=1; end;
   if bet > 0 then money(MONEY_BET):=ROUND(bet,2); end;
   if minbet > 0 AND maxbet >= minbet then money(MONEY_MIN):=ROUND(minbet,2); end;
   if maxbet >= money(MONEY_MIN) then money(MONEY_MAX):=ROUND(maxbet,2); end;
   money(MONEY_BANK):=ROUND(bank,2);

   otto:=otto-1;
   if pre(6) == 1 AND stat_collect <> 1 then D1:={}; D2:={}; D3:={}; end;
   otto_wait:=IFTE(otto,otto_wait_val(otto),0);

   post:={auto_bet,show_bet,show_hint,BS_adv,ndeck,stat_collect,meter,cardcount,unseen};
   pref_post:={pref_bet,pref_bank,pref_minbet,pref_maxbet};

   if ΣLIST(post==pre) <> SIZE(pre) then saved:=[0,0]; end;

   if ΣLIST(pref_post==pref_pre) <> SIZE(pref_pre) then
      if pref_bet <= 0 OR pref_minbet <= 0 OR pref_maxbet < pref_minbet then bad_bet:=1; end;
      if pref_bet > 0 then pref_money(MONEY_BET):=ROUND(pref_bet,2); end;
      if pref_minbet > 0 AND pref_maxbet >= pref_minbet then pref_money(MONEY_MIN):=ROUND(pref_minbet,2); end;
      if pref_maxbet >= pref_money(MONEY_MIN) then pref_money(MONEY_MAX):=ROUND(pref_maxbet,2); end;
      pref_money(MONEY_BANK):=ROUND(pref_bank,2);
      saved(2):=0;
   end;
end;


set_cut_card()
begin
   local lower,upper;
   lower:=IFTE(ndeck <= 3,220,100);
   upper:=IFTE(ndeck <= 3,240,150);
   cut_card:=CEILING((RANDINT(lower,upper)/1000)*ndeck*52);
end;


shuffle()
begin
   return IFTE(SIZE(SDECK) <= cut_card OR empty_deck_shuffle OR orig_deck <> ndeck,1,0);
end;


do_dhit()
begin
   local x,total:=0;
   for x from 1 to SIZE(PHAND) do
      total:=total+PSTATE(x,STATE_BUST)+PSTATE(x,STATE_SURR)+PSTATE(x,STATE_BJ);
   end;
   return total <> SIZE(PHAND);
end;


disp_phand(hand)
begin
   local x,xy:=POS_tbl(0,[2,1]);
   BLIT_P(G0,0,xy(2)+MIN(card_offset),G3,0,xy(2)+MIN(card_offset),max_dx,xy(2)+MAX(card_offset)+DELTAY+1);

   for x from 1 to SIZE(PHAND(hand)) do
      DRAWCARD(PHAND(hand,x),[2,x],0,0,0);
   end;
   location:=[2,x];
end;


summary()
begin
   local what,x,y,k;
   local threshold:=5;
   kresolved:=MAKELIST("",x,1,SIZE(PHAND));

   DIMGROB_P(G6,dx+1,soft_dy+1);
   BLIT_P(G6,G0);
   lastx(5):=0;

   RECT_P(0,0,dx,17,desktop);
   RECT_P(0,18,dx,50,card_back);
   LINE_P(0,18,dx,18,linecolor);

   TEXTOUT_P("Dealer",10,4,2,black);
   for k from 1 to SIZE(DHAND(1)) do
      DRAWCARD(DHAND(1,k),[1,k],1,0,0);
   end;
   PRINT_MSGBOX(IFTE(DSTATE(STATE_BUST),"Bust",""),[1,14],15,8,1,0);

   RECT_P(0,51,dx,70,desktop);
   RECT_P(0,71,dx,soft_dy,card_front);
   LINE_P(0,51,dx,51,linecolor);
   LINE_P(0,71,dx,71,linecolor);
   TEXTOUT_P("Player",10,56,2,black);
   TEXTOUT_P("Split Hand Summary",104,56,2,black);

   y:=CEILING(SIZE(PHAND)/threshold);
   x:=1;

   repeat
      page(x,y,threshold);
      what:=GETACT("summary",{(x>1 AND x<=y),(x==y)});
      case
      if what == 6 AND x <= y then x:=x+1; end;
      if what == 1 then x:=x-1; end;
      end;
   until (what == 6 AND x > y);

   BLIT_P(G0,G6);
   BLIT_P(G0,G7,nocolor);
end;


page(page_num,page_max,threshold)
begin
   local str,ret,k,m,loc_row:=2;
   local yc,x:=268,y:=56;
   local kstart:=((page_num-1)*threshold)+1;
   local kend:=kstart+threshold-1;

   if kend > SIZE(PHAND) then kend:=SIZE(PHAND); end;
   RECT_P(0,72,dx,soft_dy,card_front);

   if page_max > 1 then
      if lastx(5) <> 0 then
         RECT_P(x,y-1,x+lastx(5),y+12,desktop);
      end;
      str:=" "+page_num+" of "+page_max+" ";
      lastx(5):=TEXTOUT_P(str,G2,0,0,2);
      TEXTOUT_P(str,x,y,2,black,150,card_back);
   end;

   for k from kstart to kend do
      ret:=POS_tbl(1,[loc_row,1]);

      RECT_P(ret(1)+1,ret(2),dx,ret(2)+DELTAY-1,card_front);
      if (k MOD threshold) <> 1 then
         LINE_P(ret(1)+1,ret(2),dx,ret(2),linecolor);
      end;
      if k == SIZE(PHAND) then
         LINE_P(ret(1)+1,ret(2)+DELTAY,dx,ret(2)+DELTAY,linecolor);
      end;

      for m from 1 to SIZE(PHAND(k)) do
         DRAWCARD(PHAND(k,m),[loc_row,m],1,(m == SIZE(PHAND(k)) AND PSTATE(k,STATE_DBL)),0);
      end;

      if kresolved(k) == "" then kresolved(k):=bj_result(k); end;

      if kresolved(k) <> "Won" then //Won not displayed
         yc:=IFTE(k == SIZE(PHAND) AND (k MOD threshold),8,0);
         PRINT_MSGBOX(kresolved(k),[loc_row,14],15,9+yc,1,0);
      end;
      loc_row:=loc_row+1;
   end;
end;


bj_result(hand)
begin
   local str="";
   round_result:=0;

   case
   if DSTATE(STATE_BJ) AND PSTATE(hand,STATE_BJ) then
      str:="Push";
      round_result:=0;
      stat(STAT_TIE):=stat(STAT_TIE)+1;
      stat(STAT_BJ):=stat(STAT_BJ)+1;
   end;
   if PSTATE(hand,STATE_SURR) then
      str:="Surrender";
      round_result:=-0.5;
      money(MONEY_BANK):=money(MONEY_BANK)-(money(MONEY_BET)/2);
      stat(STAT_SURR):=stat(STAT_SURR)+1;
   end;
   if PSTATE(hand,STATE_BUST) then
      str:="Bust";
      round_result:=-1;
      money(MONEY_BANK):=money(MONEY_BANK)-money(MONEY_BET);
      stat(STAT_BUST):=stat(STAT_BUST)+1;
      stat(STAT_LOSE):=stat(STAT_LOSE)+1;
   end;
   if PSTATE(hand,STATE_BJ) then
      str:="Natural";
      round_result:=1.5;
      money(MONEY_BANK):=money(MONEY_BANK)+(money(MONEY_BET)*1.5);
      stat(STAT_BJ):=stat(STAT_BJ)+1;
      stat(STAT_WIN):=stat(STAT_WIN)+1;
   end;
   if PSTATE(hand,STATE_TOT) > DSTATE(STATE_TOT) OR DSTATE(STATE_BUST) then
      str:="Won";
      round_result:=1;
      money(MONEY_BANK):=money(MONEY_BANK)+money(MONEY_BET);
      stat(STAT_WIN):=stat(STAT_WIN)+1;
   end;
   if PSTATE(hand,STATE_TOT) < DSTATE(STATE_TOT) then
      str:="Lost";
      round_result:=-1;
      money(MONEY_BANK):=money(MONEY_BANK)-money(MONEY_BET);
      stat(STAT_LOSE):=stat(STAT_LOSE)+1;
   end;
   if PSTATE(hand,STATE_TOT) == DSTATE(STATE_TOT) then
      str:="Push";
      round_result:=0;
      stat(STAT_TIE):=stat(STAT_TIE)+1;
   end;
   end;

   if PSTATE(hand,STATE_DBL) then
      money(MONEY_BANK):=money(MONEY_BANK)+(money(MONEY_BET)*round_result);
      case
      if round_result == -1 then stat(STAT_DBLLOSS):=stat(STAT_DBLLOSS)+1; end;
      if round_result == 1 then stat(STAT_DBLWIN):=stat(STAT_DBLWIN)+1; end;
      end;
      round_result:=round_result*2;
   end;

   PSTATE(hand,STATE_RESULT):=round_result;
   data_collect(hand);
   return str;
end;


set_state(hand,tc)
begin
   local x;
   PSTATE(hand,STATE_TOT):=0;
   PSTATE(hand,STATE_ACE):=0;
   PSTATE(hand,STATE_BUST):=0;
   if tc(1) then PSTATE(hand,STATE_TC):=tc(2); end;

   for x from 1 to SIZE(PHAND(hand)) do
      PSTATE(hand,STATE_TOT):=PSTATE(hand,STATE_TOT)+CARDVAL(PHAND(hand,x));
      if ace then PSTATE(hand,STATE_ACE):=PSTATE(hand,STATE_ACE)+1; end;
   end;

   while PSTATE(hand,STATE_ACE) AND PSTATE(hand,STATE_TOT) > 21 do
      PSTATE(hand,STATE_TOT):=PSTATE(hand,STATE_TOT)-10;
      PSTATE(hand,STATE_ACE):=PSTATE(hand,STATE_ACE)-1;
   end;

   if PSTATE(hand,STATE_TOT) > 21 then PSTATE(hand,STATE_BUST):=1; end;
end;


PSPLIT(hand)
begin
   local x,c1:=PHAND(hand,1),c2:=PHAND(hand,2),tc:=PSTATE(hand,STATE_TC);
   split:=0;

   PHAND:=CONCAT(PHAND,{{c2}});
   PHAND(hand):={c1};

   c1:=RANDOMCARD(1);
   PHAND(hand):=CONCAT(PHAND(hand),{c1});
   PSTATE(hand,STATE_SPLIT):=1;
   set_state(hand,{1,tc});

   c1:=RANDOMCARD(1);
   PHAND(SIZE(PHAND)):=CONCAT(PHAND(SIZE(PHAND)),{c1});
   PSTATE(SIZE(PHAND),STATE_SPLIT):=1;
   set_state(SIZE(PHAND),{1,tc});

   disp_phand(hand);

   for x from 1 to 2 do
      DRAWCARD(PHAND(SIZE(PHAND),x),[2,x+4],0,0,0);
   end;

   stat(STAT_SPLIT):=stat(STAT_SPLIT)+1;
   deck_rounds:=deck_rounds+1;
   PRINT_PMSG("Player's Split hand");

   if ace_split then
      PSTAND();
   else
      CONT(); DRAWCARD({-2,0},[2,5],0,0,0);
   end;
end;


PSTAND()
begin
   SHOW_D_CARD();
   if do_dhit() then
      while DSTATE(STATE_TOT) < 17 do DHIT(); end;
   end;
end;


DHIT()
begin
   local card:=RANDOMCARD(1);

   DHAND(1):=CONCAT(DHAND(1),{card});
   DSTATE(STATE_TOT):=DSTATE(STATE_TOT)+CARDVAL(card);
   if ace then DSTATE(STATE_ACE):=DSTATE(STATE_ACE)+1; end;

   while DSTATE(STATE_TOT) > 21 AND DSTATE(STATE_ACE) do
      DSTATE(STATE_TOT):=DSTATE(STATE_TOT)-10;
      DSTATE(STATE_ACE):=DSTATE(STATE_ACE)-1;
   end;

   DRAWCARD(card,location,0,0,SIZE(PHAND)>1 AND NOT ace_split);
   location:=[location(1),location(2)+1];

   if DSTATE(STATE_TOT) > 21 then
      PRINT_MSGBOX("Bust",[location(1),location(2)+1],9,17,0,SIZE(PHAND)>1 AND NOT ace_split);
      DSTATE(STATE_BUST):=1;
   end;
end;


PHIT(hand)
begin
   local card:=RANDOMCARD(1);

   PHAND(hand):=CONCAT(PHAND(hand),{card});
   set_state(hand,{0});

   DRAWCARD(card,location,0,PSTATE(hand,STATE_DBL),0);
   location:=[location(1),location(2)+1];
end;


DEAL()
begin
   local card,dtot:=0,ptot:=0,dace:=0,pace:=0,d_bj:=0,p_bj:=0;
   local tc:=true_count;

   split:=0;
   ace_split:=0;
   offer_ins:=0;
   dealer_card_seen:=0;
   saved(1):=0;
   orig_bet:=money(MONEY_BET);
   copy_desktop();

   TEXTOUT_P(" Dealer ",12,4,2,black,100,card_front);
   PRINT_PMSG("Player");

   //Player 1st
   card:=RANDOMCARD(1);
   PHAND:={{card}};
   ptot:=ptot+CARDVAL(card);
   if ace then pace:=pace+1; end;
   DRAWCARD(card,[2,1],0,0,0);

   //Dealer 1st
   card:=RANDOMCARD(1);
   DHAND:={{card}};
   dtot:=dtot+CARDVAL(card);
   if ace then
      dace:=dace+1;
      offer_ins:=1;
   end;
   DRAWCARD(card,[1,1],0,0,0);

   //Player 2nd
   card:=RANDOMCARD(1);
   PHAND(1):=CONCAT(PHAND(1),{card});
   ptot:=ptot+CARDVAL(card);
   if ace then pace:=pace+1; end;
   DRAWCARD(card,[2,2],0,0,0);

   //Dealer hole card
   card:=RANDOMCARD(0);
   DHAND(1):=CONCAT(DHAND(1),{card});
   dtot:=dtot+CARDVAL(card);
   if ace then dace:=dace+1; end;
   DRAWCARD({0,card(2)},[1,2],0,0,0);

   if dtot > 21 then
      dtot:=dtot-10;
      dace:=dace-1;
   end;
   if ptot > 21 then
      ptot:=ptot-10;
      pace:=pace-1;
   end;

   if dtot == 21 then
      d_bj:=1;
   end;
   if ptot == 21 then
      p_bj:=1;
      offer_ins:=0;
   end;

   location:=[2,3];
   DSTATE:=[dtot,dace,0,d_bj];
   PSTATE:=[[ptot,pace,0,p_bj,0,0,0,0,tc,0]];
end;


MAKEDECK()
begin
   local x,names:={"one","two","three","four","five","six","seven","eight"};

   copy_desktop();
   ccount:=0;
   true_count:=0;
   seen:=0;
   deck_rounds:=0;
   saved(1):=0;
   orig_bet:=money(MONEY_BET);

   if orig_deck == ndeck then
      SDECK:=CONCAT(SDECK,DISC);
   else
      SDECK:=MAKELIST(x,x,1,ndeck*52);
      orig_deck:=ndeck;
   end;

   DISC:={};
   set_cut_card();

   for x from 1 to ndeck do
      DRAWCARD({0,card_offset(RANDINT(1,SIZE(card_offset)))},[2,x+1],1,0,0);
   end;
   PSTATUS("Shuffled "+names(ndeck)+" deck"+IFTE(ndeck > 1,"s.","."),1);

   if empty_deck_shuffle then
      empty_deck_shuffle:=0;
      PSTATUS("Reshuffle due to use of discard pile.",3);
   end;
   return;
end;


random_phrase()
begin
   local x:=RANDINT(1,200),y:=RANDINT(20,STATUSY-17);
   local phrase:={"You Rock!","Shine on!","Sing today!","Slow down.","Stay beautiful!","Carpe diem",
      "Don't panic!","Enjoy today!","Dream big!","Go for it.","Hi!","Game on!",
      "Cheers!","Smile!",CHAR(381)+"iveli!"};
   TEXTOUT_P(phrase(RANDINT(1,SIZE(phrase))),x,y,1,black,100,card_front);
end;


CARDVAL(card)
begin
   local val:=rank_value(card(1));
   ace:=0;
   case
   if val == 1 then ace:=1; return 11; end;
   if val >= 10 then return 10; end;
   return val;
   end;
end;


recount()
begin
   local i,k;
   ccount:=0;
   seen:=0;
   count_card(DHAND(1,1,1));

   if dealer_card_seen then
      for i from 2 to SIZE(DHAND(1)) do
         count_card(DHAND(1,i,1));
      end;
   end;

   for k from 1 to SIZE(PHAND) do
      for i from 1 to SIZE(PHAND(k)) do
         count_card(PHAND(k,i,1));
      end;
   end;
end;


count_card(value)
begin
   local deck_remain;
   ccount:=ccount+CCVAL(value);
   seen:=seen+1;
   deck_remain:=CEILING((ndeck*52-seen)/52);
   true_count:=IFTE(deck_remain == 0,ccount,ccount/deck_remain);
end;


RANDOMCARD(count)
begin
   local value,item;

   if SIZE(SDECK) == 0 then
      if SIZE(DISC) == 0 then
         otto:=0; game_save(); restore_format();
         MSGBOX("Empty decks. Saving and quitting.");
         KILL;
      else
         SDECK:=DISC;
         DISC:={};
         recount();
         empty_deck_shuffle:=1;
      end;
   end;

   item:=RANDINT(1,SIZE(SDECK));
   value:=SDECK(item);
   SDECK:=SUPPRESS(SDECK,item);

   if count then count_card(value); end;

   return {value,card_offset(RANDINT(1,SIZE(card_offset)))};
end;


GETACT(verb,opt)
begin
   local split_str,dbl_str,surr_str;
   local what:=CMD_NONE,event,menu:={""},i;
   local whatkey:={14,15,16,17,18,19,30};

   TOff:=TOff;
   if verb == "play" OR verb == "ins" OR verb == "inter" OR verb == "cont" then
      if verb == "play" OR verb == "cont" OR empty_deck_shuffle then shuffle_msg(); end;
      disp_card_count(0); disp_meter(); disp_bank_bet(0); otto_icon(0);
      if bad_bet then PSTATUS("Invalid bet entries ignored.",4); bad_bet:=0; end;
      if bad_ins then PSTATUS("Insurance bet cancelled.",4); bad_ins:=0; end;
   end;

   case
   if verb == "summary" AND NOT otto then
      menu:={IFTE(opt(1),"Prev",""),"","","","",IFTE(opt(2),"Cont","Next")};
   end;
   if verb == "welcome" then
      menu:={"Play","Help","Color",IFTE(opt(1),"Load",""),"Quit"};
   end;
   if verb == "stats" then
      menu:={"Deck","Discard","","","","Back"};
   end;
   if (verb == "back" OR verb == "cont") AND NOT otto then
      menu:={"","","","","",IFTE(verb=="back","Back","Cont")};
   end;
   if verb == "play" then
      split_str:=IFTE(opt(3),"Split","");
      dbl_str:=IFTE(opt(2) == 2,"DBL","");
      surr_str:=IFTE(opt(2) == 2,"Surr","");
      setup_hint(opt(1));
      menu:={IFTE(opt(1)==CMD_HIT AND (show_hint OR otto),G5,"Hit"),
             IFTE(opt(1)==CMD_STAND AND (show_hint OR otto),G5,"Stand"),
             IFTE(opt(1)==CMD_DBL AND (show_hint OR otto),G5,dbl_str),
             IFTE(opt(1)==CMD_SPLIT AND (show_hint OR otto),G5,split_str),
             IFTE(opt(1)==CMD_SURR AND (show_hint OR otto),G5,surr_str)};
   end;
   if verb == "inter" AND NOT otto then
      menu:={IFTE(shuffle(),"Shuffle","Deal"),"Bet",IFTE(opt(1,1),"",G5),IFTE(opt(1,2),"",G9),"Quit","Stats"};
   end;
   if verb == "ins" then
      setup_hint(opt(1));
      menu:={IFTE(opt(1)==CMD_YES AND (show_hint OR otto),G5,"Yes"),IFTE(opt(1)==CMD_NO AND (show_hint OR otto),G5,"No")};
   end;
   end;

   if otto then
      for i from 1 to SIZE(menu) do
         if TYPE(menu(i)) == 2 then menu(i):=""; end;
      end;
   end;

   DRAWMENU(menu);

   if otto then
      if otto_wait then WAIT(otto_wait); end;
      case
      if verb == "cont" OR verb == "summary" then return 6; end;
      if verb == "inter" then return 1; end;
      return opt(1);
      end;
   end;

   repeat
      event:=WAIT(-1);
      case
      if TYPE(event) == 0 AND event <> -1 then
         if CAS.contains(EVAL(whatkey),EVAL(event)) then
            what:=IFTE(event == 30,6,event-13);
         end;
      end;
      if TYPE(event) == 6 then
         if event(1) == 3 AND event(3) > soft_dy then
            what:=IP(event(2)/53.3)+1;
         end;
      end;
      end;
   until what <= SIZE(menu) AND SIZE(menu(what)) <> 0;

   return what;
end;


CANSPLIT(hand)
begin
   local c1:=CARDVAL(PHAND(hand,1)),c2:=CARDVAL(PHAND(hand,2));
   ace_split:=0;
   if c1 == c2 then
      if ace AND SIZE(PHAND) == 1 then ace_split:=1; end;
      return 1;
   end;
   return 0;
end;


PSTATUS(text,where)
begin
   if where > 4 then return; end;
   if lastx(5+where) <> 0 then
      RECT_P(STATUSX,STATUSY-1+16*(where-1),STATUSX+lastx(5+where),STATUSY-1+16*where,statusarea);
   end;
   lastx(5+where):=TEXTOUT_P(text,G2,0,0,2);
   TEXTOUT_P(text,STATUSX,STATUSY+16*(where-1),2,black);
   last_pstatus(where):=text;
end;


SHOW_D_CARD()
begin
   count_card(DHAND(1,2,1));
   dealer_card_seen:=1;

   DRAWCARD(DHAND(1,2),[1,2],0,0,SIZE(PHAND)>1 AND NOT ace_split);
   if DSTATE(STATE_BJ) then
      PRINT_MSGBOX("Natural",[1,4],9,17,0,SIZE(PHAND)>1 AND NOT ace_split);
   end;

   location:=[1,3];
end;


PRINT_MSGBOX(val,location,adjustment_x,adjustment_y,sum_tbl,summary)
begin
   local x,y,xsize,ret:=POS_tbl(sum_tbl,location);
   if val == "" then return; end;

   x:=(ret(1)+adjustment_x) MOD (max_dx+1);
   y:=ret(2)+adjustment_y;
   val:=" "+val+" ";
   xsize:=TEXTOUT_P(val,G2,0,0,2);
   RECT_P(IFTE(summary,G7,G0),x-2,y-2,x+xsize+2,y+13,black,card_front);
   TEXTOUT_P(val,IFTE(summary,G7,G0),x,y,2,black);
end;


rank_value(card)
begin
   return IFTE(card <= 0,card,((card-1) MOD 13)+1);
end;


CCVAL(card)
begin
   local val:=rank_value(card);
   case
   if val >=10 OR val == 1 then return -1; end;
   if val >= 7 then return 0; end;
   return 1;
   end;
end;


POS_tbl(sum_tbl,index)
begin
   local x:=9,y:=21,xo:=17,yo1,yo2:=29;
   yo1:=IFTE(sum_tbl,53,74);
   return {x+xo*(index(2)-1),IFTE(index(1)==1,y,y+yo1+yo2*(index(1)-2))};
end;


DRAWCARD(card,position,sum_tbl,draw_dbl,summary)
begin
   local starty,xy;
   local value,suit,offset;

   value:=rank_value(card(1));
   suit:=(((IP((card(1)-1)/13)+1)-1) MOD 4) + 1;
   offset:=card(2);

   xy:=POS_tbl(sum_tbl,position);

   starty:=xy(2);
   if NOT sum_tbl OR value == 0 then xy(2):=xy(2)+offset; end;

   case
   if value < 0 then // Erase card
      BLIT_P(xy(1),starty+MIN(card_offset),G3,xy(1),starty+MIN(card_offset),(xy(1)+DELTAX+1)*ABS(value),starty+MAX(card_offset)+DELTAY+1);
      return;
   end;
   if value == 0 then // Dealer back
      BLIT_P(xy(1),xy(2),G1,LART(1,1),LART(1,2),LART(1,3),LART(1,4),nocolor);
      return;
   end;
   end;

   makecard(value,suit);

   if draw_dbl then
      ROTATE(G2,90,nocolor);
      LINE_P(G2,DELTAY,1,DELTAY,DELTAX-1,black);
   end;

   BLIT_P(IFTE(summary,G7,G0),(xy(1) MOD (max_dx+1)),xy(2),G2,nocolor);
end;


makecard(value,suit)
begin
   local color;
   DIMGROB_P(G2,DELTAX+1,DELTAY+1,nocolor);
   BLIT_P(G2,G1,LART(2,1),LART(2,2),LART(2,3),LART(2,4));
   color:=IFTE(suit == S_DIAMOND OR suit == S_HEART,red,black);
   case
   if value == 10 then TEXTOUT_P( 10,G2,2,2,2,color); end;
   if value == 12 then TEXTOUT_P("Q",G2,4,2,2,color); end;
   if value == 11 then TEXTOUT_P("J",G2,5,2,2,color); end;
   if value == 13 then TEXTOUT_P("K",G2,5,2,2,color); end;
   if value == 1 then  TEXTOUT_P("A",G2,5,2,2,color); end;
   TEXTOUT_P(value,G2,5,2,2,color);
   end;
   TEXTOUT_P(SUIT(suit),G2,3,16,2,color);
end;


draw_bit_art(pic,bcolor)
begin
   local x,y,z,c,item,cloud;
   local mirror:=0;
   local rand:=RANDINT(1,6) MOD 2;
   local offset:=[15,17,16,8,13,11,13,1,4];
   local border:=black,pix:=white;
   BITART:={};

   item:=CAS.contains(EVAL(INSTRING({"Yes","No","Hit","Stand","DBL","Split","Surr","GAME","PREF"},pic)),1);
   case
   if pic == "hint" OR pic == "save" then
      x:=#020202h;
      if dark then
         border:=#F2F2F2h; pix:=#191919h; bcolor:=#808080h; x:=#030303h;
         if pic == "hint" then
            bcolor:=#202020h; x:=#040404h;
         end;
      end;
      DIMGROB_P(G4,GROBW_P(G5),GROBH_P(G5));
      c:=bcolor-IFTE(pic == "hint" AND NOT dark,#282828h,#0h);
      for y from 2 to GROBH_P(G4)-2 do
         LINE_P(G4,1,y,GROBW_P(G4)-2,y,c);
         c:=c+x;
      end;
      RECT_P(G4,0,1,GROBW_P(G4)-1,GROBH_P(G4)-1,border,{white,255});

      PIXON_P(G4,1,2,border); PIXON_P(G4,2,2,border);
      LINE_P(G4,0,1,2,1,pix);
      PIXON_P(G4,0,2,pix);

      PIXON_P(G4,1,GROBH_P(G4)-2,border); PIXON_P(G4,2,GROBH_P(G4)-2,border);
      LINE_P(G4,0,GROBH_P(G4)-1,2,GROBH_P(G4)-1,pix);
      PIXON_P(G4,0,GROBH_P(G4)-2,pix);

      PIXON_P(G4,GROBW_P(G4)-2,2,border); PIXON_P(G4,GROBW_P(G4)-3,2,border);
      LINE_P(G4,GROBW_P(G4)-1,1,GROBW_P(G4)-3,1,pix);
      PIXON_P(G4,GROBW_P(G4)-1,2,pix);

      PIXON_P(G4,GROBW_P(G4)-2,GROBH_P(G4)-2,border); PIXON_P(G4,GROBW_P(G4)-3,GROBH_P(G4)-2,border);
      LINE_P(G4,GROBW_P(G4)-1,GROBH_P(G4)-1,GROBW_P(G4)-3,GROBH_P(G4)-1,pix);
      PIXON_P(G4,GROBW_P(G4)-1,GROBH_P(G4)-2,pix);
      return;
   end;
   if item then
      x:=IFTE(pic == "GAME" OR pic == "PREF",5,4);
      BLIT_P(G4,G1,LART(x,1),LART(x,2),LART(x,3),LART(x,4));
      case
      if x == 5 then
         TEXTOUT_P("Save "+pic,G4,offset(item),7,1,IFTE(dark,#191919h,#F2F2F2h));
      end;
      TEXTOUT_P(pic,G4,offset(item),3,3,IFTE(dark,#F2F2F2h,#191919h));
      end;
      return;
   end;
   if pic == "card" then
      DIMGROB_P(G4,DELTAX+1,DELTAY+1);
      RECT_P(G4,0,0,DELTAX,DELTAY,black,bcolor);

      PIXON_P(G4,1,1,black);
      PIXON_P(G4,1,DELTAY-1,black);
      PIXON_P(G4,0,0,nocolor);
      PIXON_P(G4,0,DELTAY,nocolor);

      PIXON_P(G4,DELTAX-1,1,black);
      PIXON_P(G4,DELTAX-1,DELTAY-1,black);
      PIXON_P(G4,DELTAX,DELTAY,nocolor);
      PIXON_P(G4,DELTAX,0,nocolor);
      return;
   end;
   if pic == "thisle" then
      BITART(1):= "   212   ";
      BITART(2):= " 21 2 12 ";
      BITART(3):= "  22122  ";
      BITART(4):= "   111   ";
      BITART(5):= "  2 1 2  ";
      BITART(6):= "  1   1  ";
      BITART(7):= "    1    ";
      BITART(8):= "    1    ";
      BITART(9):= "13  1    ";
      BITART(10):=" 13  1  1";
      BITART(11):=" 13  1   ";
      BITART(12):="  13 1  1";
      BITART(13):="  13 1  1";
      BITART(14):="1     1  ";
      BITART(15):=" 1 13 1 1";
      BITART(16):="  1 131 1";
      BITART(17):="   1  1 1";
      BITART(18):="   11111 ";
      BITART(19):="     1111";
      mirror:=1;
   end;
   if pic == "grass" then
      BITART(1):=" 13  1   ";
      BITART(2):="  13 1  1";
      BITART(3):="  13 1  1";
      BITART(4):="1     1  ";
      BITART(5):=" 1 13 1 1";
      BITART(6):="  1 131 1";
      BITART(7):="   1  1 1";
      BITART(8):="   11111 ";
      BITART(9):="     1111";
      mirror:=1;
   end;
   if pic == "back" then
      BITART(1):= "   1 1 1 1 1   ";
      BITART(2):= " 11   1 1   11 ";
      BITART(3):= "   1 1 1 1 1   ";
      BITART(4):= " 1           1 ";
      BITART(5):= "1 1 1 1 1 1 1 1";
      BITART(6):= " 1           1 ";
      BITART(7):= " 1 1 1 1 1 1 1 ";
      BITART(8):= " 1           1 ";
      BITART(9):= "1 1 1 1 1 1 1 1";
      BITART(10):=" 1           1 ";
      BITART(11):=" 1 1 1 1 1 1 1 ";
      BITART(12):=" 1           1 ";
      BITART(13):="1 1 1 1 1 1 1 1";
      BITART(14):=" 1           1 ";
      BITART(15):=" 1 1 1 1 1 1 1 ";
      BITART(16):=" 1           1 ";
      BITART(17):="1 1 1 1 1 1 1 1";
      BITART(18):=" 1    1 1    1 ";
      BITART(19):="   1 1 1 1 1   ";
      BITART(20):=" 1  1 1 1 1  1 ";
   end;
   if pic == "welcome" then
      BITART(1):= "1                   1          1                                             ";
      BITART(2):= " 11                11          11                                            ";
      BITART(3):= "  11              11           11                                            ";
      BITART(4):= "   11            11            1                                             ";
      BITART(5):= "   11           11    111     11     1111     1111       111  111       111  ";
      BITART(6):= "    11     1    11  11   11   11   11       11    11   11   11   11   11   11";
      BITART(7):= "     11   111  11   11 1111    1   11       11    11   11   11   11   111111 ";
      BITART(8):= "     11  11  1 11   11        11   11       11    11   11        11   11     ";
      BITART(9):= "      111    111    11        11   11       11   11    11        11   11     ";
      BITART(10):="      1       1       1111    11     1111     111      11        11     1111 ";
   end;
   if pic == "line" then
      BITART(1):=" 11                                                     22        222                            22              222         11      ";
   end;
   if pic == "moon" then
      BITART(1):= "         161661661  ";
      BITART(2):= "       1666666666661";
      BITART(3):= "      6666661       ";
      BITART(4):= "    16666666        ";
      BITART(5):= "  66666661          ";
      BITART(6):= " 16666666           ";
      BITART(7):= " 66666666           ";
      BITART(8):= "1666666661          ";
      BITART(9):= " 666666666          ";
      BITART(10):=" 1666666666         ";
      BITART(11):="   666666661        ";
      BITART(12):="   1666666666       ";
      BITART(13):="     6666666661     ";
      BITART(14):="      16666666666661";
      BITART(15):="        6166616661  ";
      mirror:=1;
   end;
   if pic == "sun" then
      BITART(1):= "                        1                           ";
      BITART(2):= "       1                                1           ";
      BITART(3):= "         1              1             1             ";
      BITART(4):= "           1                       1                ";
      BITART(5):= "                        1        1            1     ";
      BITART(6):= "              1      1 1 1 1 1             1        ";
      BITART(7):= "                   1144444444441       1            ";
      BITART(8):= "1                 144444444444441                 1 ";
      BITART(9):= "     1          144444444444444444 1          1     ";
      BITART(10):="          1   1444444444444444444441     1          ";
      BITART(11):="             1444444444444444444444441              ";
      BITART(12):="             1444444444444444444444441              ";
      BITART(13):="       1    144444444444444444444444441   1         ";
      BITART(14):="    1        1444444444444444444444441         1    ";
      BITART(15):="1            1444444444444444444444441             1";
      BITART(16):="               144444444444444444441                ";
      BITART(17):="            1  144444444444444444441   1            ";
      BITART(18):="        1        14444444444444441          1       ";
      BITART(19):="   1              14444444444441                1   ";
      BITART(20):="               1   1 1 1   1 1 1   1                ";
      BITART(21):="              1          1                          ";
      BITART(22):="                                      1             ";
      BITART(23):="            1            1                          ";
      BITART(24):="                                         1          ";
      BITART(25):="          1              1                 1        ";
   end;
   if pic == "bug" then
      BITART(1):= "111    1       1   111";
      BITART(2):= "12221  1  11  1   1221";
      BITART(3):= " 12121   1441   12121 ";
      BITART(4):= "   122 1444441 12221  ";
      BITART(5):= "     12214444412221   ";
      BITART(6):= "       1  414  11     ";
      BITART(7):= "         1   1        ";
      mirror:=1;
   end;
   if pic == "cloud" then
      BITART(1):= "                         6 6 66   66           ";
      BITART(2):= "                     6  6......6.....6         ";
      BITART(3):= "                   6....................6      ";
      BITART(4):= "                  6......................6     ";
      BITART(5):= "                  6........................6   ";
      BITART(6):= "                6..........................6   ";
      BITART(7):= "          6  6 6...........66................6 ";
      BITART(8):= "     6 6 6...................66.............6  ";
      BITART(9):= "    6..........................6.............6 ";
      BITART(10):="  6.............................6.............6";
      BITART(11):=" 6..............................6 6..........6 ";
      BITART(12):="6........6.....66 6.........6 6     6.......6  ";
      BITART(13):=" 6 6  66  6 6 6    66 6 6  6          66 6 6   ";
      cloud:={white,#F0F0F0h,white,#E6E6E6h,white,white};
      c:=cloud(RANDINT(1,SIZE(cloud)));
      mirror:=1;
   end;
   if pic == "otto" then
      BITART(1):= "                11            11         ";
      BITART(2):= "              11            11           ";
      BITART(3):= "    1111111111111111111111111111111111   ";
      BITART(4):= "  1111111,,,,,,,,,,1111,,,,,,,,,,111111  ";
      BITART(5):= " 11111111,,,,,,,,,,1111,,,,,,,,,,111111  ";
      BITART(6):= " 11111111,,,,,,,,,,1111,,,,,,,,,,11111111";
      BITART(7):= "1111111111111,,,,,,111111111,,,,,11111111";
      BITART(8):= "1111111111111,,,,,,111111111,,,,,11111111";
      BITART(9):= "1111111111111111111111111111111111111111 ";
      BITART(10):=" 11111111111111111111111111111111111111  ";
      BITART(11):="   111111,,,,,,,,,,,,,,,,,,,,,,,,11111   ";
      BITART(12):="    11111111,,,,,,,,,,,,,,,,,,,1111111   ";
      BITART(13):="    111111111111111111111111111111111    ";
      BITART(14):="     1111111111111111111111111111111     ";
      mirror:=1;
   end;
   return;
   end;

   DIMGROB_P(G4,SIZE(BITART(1))+1,SIZE(BITART)+1,nocolor);

   for y from 1 to SIZE(BITART) do
      for x from 1 to SIZE(BITART(y)) do
         z:=IFTE(mirror AND rand,SIZE(BITART(y))-x+1,x);
         item:=CHAR(BITART(y,z));
         case
         if item == "1" then PIXON_P(G4,x,y,black); end;
         if item == "2" then PIXON_P(G4,x,y,mag); end;
         if item == "3" then PIXON_P(G4,x,y,#13F707h); end;
         if item == "4" then PIXON_P(G4,x,y,#F6FA02h); end;
         if item == "." then PIXON_P(G4,x,y,c); end;
         if item == "," then PIXON_P(G4,x,y,white); end;
         if item == "6" then PIXON_P(G4,x,y,#ADAAAAh); end;
         end;
      end;
   end;
end;


Plot(cmd,unseen)
begin
   local deck:=IFTE(cmd == CMD_DECK,SDECK,DISC);
   local ticks,color;
   local total:=SIZE(deck);
   local x,y,xoff,i,j,str;
   local biggest,correction,y_scale,y_deck,deck_graph_y;

   bucket:={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   getdata(deck);
   biggest:=MAX(bucket);

   Xmin:=-10;
   Xmax:=150;

   case
   if biggest == 0 then biggest:=1; end;
   if biggest <= 8 then end;
   if biggest MOD 2 then biggest:=biggest+1; end;
   end;
   case
   if biggest == 22 then biggest:=24; end;
   if biggest == 26 then biggest:=28; end;
   end;

   Ymin:=-biggest;
   Ymax:=biggest+0.75*biggest;

   RECT_P(0,0,dx,soft_dy,card_front);
   RECT_P(0,166,dx,soft_dy,card_back);
   LINE(0,0,0,biggest,black);

   ticks:=find_lcm(biggest);
   for i from 1 to ticks(2) do
      LINE(0,i*ticks(1),-1,i*ticks(1),black);
   end;

   x:=0;
   xoff:=CEILING(100/13);
   y_scale:=biggest/18;
   correction:=IFTE(biggest >= 10,-2,0);

   RECT_P(0,0,dx,20,desktop);
   TEXTOUT_P(IFTE(cmd==CMD_DECK,"Deck Stats","Discard Pile Stats"),IFTE(cmd==CMD_DECK,131,114),4,2,black);
   LINE_P(0,20,dx,20,linecolor);
   LINE_P(0,166,dx,166,linecolor);
   TEXTOUT(0,-5,y_scale,1,black);
   TEXTOUT(biggest,-5+correction,biggest+y_scale,1,black);

   for i from 2 to SIZE(bucket) do
      if i == 7 OR i == 10 then x:=x+xoff; end;
      y:=bucket(i);
      RECT(x,0,x+xoff,y,IFTE(y == 0,red,black),IFTE(i MOD 2,card_back,desktop));
      correction:=IFTE(y < 10,5,7);
      TEXTOUT(y,(x+xoff-correction),y+2.25*y_scale,1,black);

      case
      if i == 14 then str:="A"; end;
      if i == 11 then str:="J"; end;
      if i == 12 then str:="Q"; end;
      if i == 13 then str:="K"; end;
      str:=STRING(i);
      end;
      case
      if i == 10 then correction:=-1; end;
      if i == 11 then correction:=1; end;
      correction:=0;
      end;

      TEXTOUT(str,(x+xoff/3)+correction,-y_scale,2,black);
      x:=x+xoff;
   end;

   LINE_P(21,45,21,40,black);
   LINE_P(21,40,259,40,black);
   LINE_P(259,40,259,45,black);
   TEXTOUT_P(" Card Rank Totals ",99,35,1,black,200,card_front);

   deck_graph_y:=PX→C(21,40);

   // redfine biggest for deck
   biggest:=deck_graph_y(2);
   LINE(Xmax-20+xoff,0,Xmax-20+xoff,biggest,black);

   y_deck:=biggest*(total/(ndeck*52));
   color:=IFTE(y_deck == 0,red,black);
   RECT(Xmax-20,0,Xmax-20+xoff,y_deck,color,statusarea);
   TEXTOUT((ndeck*52),Xmax-20+xoff+2,biggest+y_scale,1,black);
   TEXTOUT(0,Xmax-20+xoff+3,y_scale,1,black);

   case
   if total < 10 then correction:=3; end;
   if total > 99 then correction:=-2; end;
   correction:=1;
   end;

   j:=biggest/ndeck;
   for i from 1 TO ndeck do
      LINE(Xmax-20+xoff,i*j,Xmax-19+xoff,i*j,black);
   end;

   TEXTOUT(total,Xmax-20+correction,y_deck+y_scale*2.25,1,black);
   TEXTOUT(IFTE(cmd==CMD_DECK,"Deck","Discard"),IFTE(cmd==CMD_DECK,Xmax-22,Xmax-25),-y_scale,2,black);

   if cmd == CMD_DECK then
      y:=(biggest*cut_card)/(ndeck*52);
      LINE(Xmax-20,y,Xmax-20-1,y,black);
      color:=IFTE(total <= cut_card,red,black);
      TEXTOUT(CHAR(8635),Xmax-20-7,y+0.04*biggest,2,color);
      LINE(Xmax-20,y,Xmax-20,0,black);

      color:=IFTE(ccount < 0,red,black);
      TEXTOUT_P("Card Count:",21,173,2,black);
      TEXTOUT_P(ccount,89,173,2,color);
      TEXTOUT_P("True Count:",22,188,2,black);
      TEXTOUT_P(STRING(true_count,6,2,0),89,188,2,color);
      TEXTOUT_P(CHAR(8635)+" - Shuffle threshold (cut card)",87,204,1,black);
   else
      TEXTOUT_P("✓",9,174,2,black);
      TEXTOUT_P("Discard Pile will be used if",21,176,1,black);
      TEXTOUT_P("the deck becomes empty.",21,189,1,black);
   end;

   TEXTOUT_P("Decks "+IFTE(cmd==CMD_DECK,"Remaining","Discarded")+":",IFTE(cmd==CMD_DECK,170,173),173,2,black);
   i:=total/52;
   TEXTOUT_P(REPLACE(IFTE(i <> 0 AND i < 0.1,"< 1/5",STRING(i,20,1,0)),"+"," "),268,173,2,black);
   TEXTOUT_P("Deck Round:",196,188,2,black);
   TEXTOUT_P(STRING(deck_rounds,1,0,0),268,188,2,black);
end;


getdata(deck)
begin
   local i,value;
   for i from 1 to SIZE(deck) do
      value:=rank_value(deck(i));
      if value == 1 then value:=14; end;
      bucket(value):=bucket(value)+1;
   end;
end;


find_lcm(value)
begin
   local i,k:=0;
   if value == 1 then return {1,1}; end;
   for i from 2 to 8 do
      if CAS.lcm(EVAL(value),EVAL(i)) == value then k:=i; end;
   end;
   if k == 0 then k:=4; end;
   return {value/k,k};
end;